package com.example.springboot.netty.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * <p> netty服务配置类
 * <p>
 * <p>
 * @author Zhang.Z
 * @version 2025-09-21
 */
@Component
public class WebSocketNettyServer {

    private final int port = 8091; // Netty端口,需要自定义，不要和服务端口冲突

    /**
     * 负责 接受客户端连接（accept）
     * <p>只做一件事：监听端口，有新的客户端连接就注册给 workerGroup 处理
     * <p>通常线程数很少，一般 1-2 个即可，因为它不是处理业务的
     */
    private EventLoopGroup bossGroup;

    /**
     * 负责 处理已经建立的连接的 I/O 事件（读写数据、业务逻辑）
     * <p> 每个连接都会绑定到 worker 的线程上处理
     * <p> 线程数可以多一些，一般默认是 CPU 核数 × 2
     *
     */
    private EventLoopGroup workerGroup;

    @PostConstruct
    public void start() {
        new Thread(this::runServer).start(); // 使用单独线程启动Netty
    }

    private void runServer() {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                     .channel(NioServerSocketChannel.class)
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                         @Override
                         protected void initChannel(SocketChannel ch) {
                             ChannelPipeline pipeline = ch.pipeline();
                             pipeline.addLast(new HttpServerCodec());
                             pipeline.addLast(new HttpObjectAggregator(65536));
                             pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); // ws路径
                             pipeline.addLast(new WebSocketFrameHandler());
                         }
                     });

            ChannelFuture future = bootstrap.bind(port).sync();
            System.out.println("Netty WebSocket server started at port " + port);
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            shutdown();
        }
    }

    @PreDestroy
    public void shutdown() {
        if (bossGroup != null) bossGroup.shutdownGracefully();
        if (workerGroup != null) workerGroup.shutdownGracefully();
        System.out.println("Netty WebSocket server stopped.");
    }

    // WebSocket处理
    private static class WebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {
            System.out.println("Received: " + msg.text());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("Echo: " + msg.text()));
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
            cause.printStackTrace();
            ctx.close();
        }
    }
}